﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml.Linq;

namespace ExcelFileQueryTool
{
    public sealed class ClientConclusionData
    {
        public string Name { get; set; }

        public DateTime GeneratedTime { get; set; }

        public DateTime FileLastModifiedTime { get; set; }

        public decimal UnpaidAmount { get; set; }
    }

    public static class ClientConclusionCacheService
    {
        private static readonly Object SyncRoot = new Object();

        /// <summary>
        /// cache data file in xml format
        /// </summary>
        private volatile static string DATA_FILE = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ClientConclusionCache.dat");

        private const string ATTR_NAME = "name";
        private const string ATTR_GENTIME = "gen_time";
        private const string ATTR_LASTMOD = "file_last_mod_time";
        private const string ATTR_UNPAID = "unpaid";
        private const string Item_Cache = "cache";

        private volatile static XDocument Caches;


        static ClientConclusionCacheService()
        {
            if (File.Exists(DATA_FILE) == false)
            {
                Caches = XDocument.Parse("<?xml version=\"1.0\" encoding=\"utf - 8\" ?><Conclusion></Conclusion>");
                Caches.Save(DATA_FILE);
            }
            else
            {
                Caches = XDocument.Load(DATA_FILE, LoadOptions.None);
            }
        }

        /// <summary>
        /// in memory operation
        /// </summary>
        /// <param name="data"></param>
        public static void Save(ClientConclusionData data)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            if (string.IsNullOrEmpty(data.Name))
                throw new ArgumentNullException("data.Name");

            lock (SyncRoot)
            {
                var ele = Caches.Root.Elements().FirstOrDefault(x => x.Attribute("name").Value == data.Name);

                if (ele == null)
                {
                    ele = new XElement(Item_Cache);
                    ele.SetAttributeValue(ATTR_NAME, data.Name);
                    Caches.Root.Add(ele);
                }

                ele.SetAttributeValue(ATTR_GENTIME, data.GeneratedTime);
                ele.SetAttributeValue(ATTR_LASTMOD, data.FileLastModifiedTime);
                ele.SetAttributeValue(ATTR_UNPAID, data.UnpaidAmount);
            }
        }

        /// <summary>
        /// in memory operation
        /// </summary>
        /// <param name="data"></param>
        public static void Delete(string name)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            lock (SyncRoot)
            {
                var ele = Caches.Root.Elements().FirstOrDefault(x => x.Attribute("name").Value == name);

                if (ele != null)
                {
                    ele.Remove();
                }                
            }
        }

        public static ClientConclusionData Get(string name)
        {
            if (string.IsNullOrEmpty(name))
                return null;

            var ele = Caches.Root.Elements().FirstOrDefault(x => x.Attribute("name").Value == name);

            if (ele == null)
                return null;

            var data = new ClientConclusionData();
            data.Name = name;
            data.GeneratedTime = DateTime.Parse(ele.Attribute(ATTR_GENTIME).Value);
            data.FileLastModifiedTime = DateTime.Parse(ele.Attribute(ATTR_LASTMOD).Value);
            data.UnpaidAmount = decimal.Parse(ele.Attribute(ATTR_UNPAID).Value);

            return data;
        }

        public static void FlushToFile()
        {
            Caches.Save(DATA_FILE);
        }
    }
}
